讓我們沿用上一篇轉接頭的例子,在之前我們都一直是以「螢幕」作為一端去跟電腦做連線,假設現在我們把範圍擴大,將螢幕做分類,可能有不同規格類型的螢幕會需要跟電腦做連線,這時該怎麼辦呢?
聰明的你,如果有想到用昨天的「Strategy」模式去做變型,那真的是吸收相當快速啊~沒錯!我們讓 ScreenService
變成一個抽象類別,並且去引用 Adapter,這樣不同規格類型的螢幕只要都去繼承 ScreenService
,然後在各自去做自己的實作,就成功了!
將抽象與實作解耦合,使它們都可以獨立地變化。
(圖片來源:https://www.bogotobogo.com/DesignPatterns/images/bridge/bridgediagram.png)
這邊我做了以下幾點的改變
ScreenService
變成抽象類別,在建構子中去帶入 Adapter
。ScreenSwitchDic
,主要是因為在 Bridge模式中,他的概念比較偏向是當下才去做 Adapter的帶入。例如在昨天的範例中,我在 main 裡面第一段便是 string screenSpec = "AVG"
; 我可以直接透過字典去找到對應規格,但在這個範例中,ScreenService screen_avg = new Screen_AVG(new HDMIAdapter());
我是在建立一個 Screen_AVG
類別時就要一同決定好需要帶入什麼的 Adapter
。using System;
using System.Collections.Generic;
namespace DAY10_Bridge
{
class Program
{
static void Main(string[] args)
{
// 透過繼承自 ScreenService,可以實例化類別並做方法改寫,且在建構時先將要使用的 adapter 帶入
ScreenService screen_avg = new Screen_AVG(new HDMIAdapter());
screen_avg.UseAdapter();
ScreenService screen_vga = new Screen_VGA(new USBAdapter());
screen_vga.UseAdapter();
ScreenService screen_dvi = new Screen_DVI(new DisplayPortAdapter());
screen_dvi.UseAdapter();
}
}
public abstract class ScreenService
{
protected Adapter _adapter;
// 建構時便將 Adapter 帶入做聚合,讓之後要做繼承去實例化的類別可以直接使用 _adapter
protected ScreenService(Adapter adapter)
{
this._adapter = adapter;
}
public abstract void UseAdapter();
}
public class Screen_AVG : ScreenService
{
public Screen_AVG(Adapter adapter) : base(adapter)
{
}
public override void UseAdapter()
{
Console.WriteLine("我是Screen_AVG,我要使用轉接器做轉接囉!");
_adapter.Switch(this.GetType().Name);
}
}
public class Screen_VGA : ScreenService
{
public Screen_VGA(Adapter adapter) : base(adapter)
{
}
public override void UseAdapter()
{
Console.WriteLine("我是Screen_VGA,我要使用轉接器做轉接囉!");
_adapter.Switch(this.GetType().Name);
}
}
public class Screen_DVI : ScreenService
{
public Screen_DVI(Adapter adapter) : base(adapter)
{
}
public override void UseAdapter()
{
Console.WriteLine("我是Screen_DVI,我要使用轉接器做轉接囉!");
_adapter.Switch(this.GetType().Name);
}
}
public interface Adapter
{
void Switch(string screenSpec);
}
public class DisplayPortAdapter : Adapter
{
public void Switch(string screenSpec)
{
Console.WriteLine($"已將{screenSpec}轉換成DisplayPort!");
}
}
public class USBAdapter : Adapter
{
public void Switch(string screenSpec)
{
Console.WriteLine($"已將{screenSpec}轉換成USB!");
}
}
public class HDMIAdapter : Adapter
{
public void Switch(string screenSpec)
{
Console.WriteLine($"已將{screenSpec}轉換成HDMI!");
}
}
}
Strategy | Bridge | |
---|---|---|
目的 | 拆解實體類與 Behavior 的耦合性 | 拆解 Abstraction 和 Implementation 的耦合性 |
類型 | 物件行為 | 物件結構 |
從今天的內容可以發現,Bridge模式遵循著兩個設計模式的大原則
如果就定義上「將抽象與實作解耦合,使它們都可以獨立地變化」,看起來很矛盾,但以上面的例子來看,又不會覺得那麼奇怪了,抽象也就是讓我的螢幕能有很多種類,且都繼承自同個抽象類別,實作就是去實作抽象類別中定義的方法,並將這些實作都用介面去做約束,最後在抽象類別中去聚合介面,就達成抽象與實作解偶了,所以我的不同螢幕都可以去自由搭配所需的轉接器!
相向經過今天的介紹,是不是對設計模式越來越有感覺了,我們明天再繼續吧~